﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System.Collections.Specialized;
using Android.Graphics;
using CoachingOrganizer.Logic.Models.Tools.EmotionsPack;

namespace CoachingOrganizer.Android.Adapters.Tools.EmotionsPack
{
    public class EmotionsPackGalleryAdapter : BaseAdapter
    {
        private readonly Activity _context;
        private readonly EmotionsPackModel _model;
        private List<EmotionTraceItemModel> _items = new List<EmotionTraceItemModel>();
        private Dictionary<View, Bitmap> _bitmapsCache = new Dictionary<View, Bitmap>();

        public EmotionsPackGalleryAdapter(Activity context, EmotionsPackModel model)
            : base()
        {
            _context = context;
            _model = model;
            IEnumerable<EmotionTraceItemModel> items = _model.EnumerateEmotionTraceItems();
            _items = items == null ? new List<EmotionTraceItemModel>() : items.Where(FilterEmotionTraceItem).ToList();
            _model.EmotionTraceItemsCollectionChanged += Model_EmotionTraceItemsCollectionChanged;
            _model.SelectedEmotionChanged += Model_SelectedEmotionChanged;
        }

        public override Java.Lang.Object GetItem(int position)
        {
            return position;
        }

        public override long GetItemId(int position)
        {
            return position;
        }

        public override int Count
        {
            get { return _items.Count; }
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View view = _context.LayoutInflater.Inflate(Resource.Layout.EmotionsPackGalleryItemLayout, parent, false);
            HookModelToView(view, _items[position]);
            return view;
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            _bitmapsCache.Clear();
        }

        private void HookModelToView(View view, EmotionTraceItemModel emotionTraceItemModel)
        {
            ImageView emotionsPackGalleryItemImageView = view.FindViewById<ImageView>(Resource.Id.emotionsPackGalleryItemImageView);
            ClearCache(view);
            SetBitmap(view, emotionTraceItemModel);
        }

        private void SetBitmap(View view, EmotionTraceItemModel emotionTraceItemModel)
        {
            ImageView emotionsPackGalleryItemImageView = view.FindViewById<ImageView>(Resource.Id.emotionsPackGalleryItemImageView);
            global::Android.Graphics.Bitmap bitmap;
            if (_bitmapsCache.ContainsKey(view))
                bitmap = _bitmapsCache[view];
            else
            {
                bitmap = global:: Android.Graphics.BitmapFactory.DecodeByteArray(emotionTraceItemModel.TracePicture, 0, emotionTraceItemModel.TracePicture.Length);
                _bitmapsCache.Add(view, bitmap);
            }
            emotionsPackGalleryItemImageView.SetImageBitmap(bitmap);
        }

        private void ClearCache(params View[] itemsToKeep)
        {
            bool hasDisposed = false;
            foreach (View item in _bitmapsCache.Keys.ToArray())
            {
                if (!itemsToKeep.Contains(item))
                {
                    global::Android.Graphics.Bitmap bitmap = _bitmapsCache[item];
                    _bitmapsCache.Remove(item);
                    bitmap.Dispose();
                    hasDisposed = true;
                }
                if (hasDisposed)
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
        }

        private bool FilterEmotionTraceItem(EmotionTraceItemModel emotionTraceItemModel)
        {
            EmotionTraceModel selectedEmotion = _model.SelectedEmotion;
            return selectedEmotion == null ? false : emotionTraceItemModel.GetEmotionName() == selectedEmotion.EmotionName;
        }

        private void Model_SelectedEmotionChanged(object sender, EventArgs e)
        {
            IEnumerable<EmotionTraceItemModel> items = _model.EnumerateEmotionTraceItems();
            _items = items == null ? new List<EmotionTraceItemModel>() : items.Where(FilterEmotionTraceItem).ToList();
            NotifyDataSetChanged();
        }

        private void Model_EmotionTraceItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    _items.AddRange(e.NewItems.OfType<EmotionTraceItemModel>().Where(FilterEmotionTraceItem));
                    break;
                case NotifyCollectionChangedAction.Remove:
                    e.OldItems.OfType<EmotionTraceItemModel>().ToList().ForEach(i =>
                        _items.Remove(i));
                    break;
                default:
                    break;
            }
            NotifyDataSetChanged();
        }
    }
}